#!/usr/bin/env python

import os.path
import re
import sys

import ipc_sm_782
from jinja2 import Environment, FileSystemLoader

basedir=os.path.dirname(__file__)

env = Environment(
    loader=FileSystemLoader(os.path.join(basedir, 'templates')),
    lstrip_blocks=True,
)
env.globals["rnd2"] = lambda x: round(x, 2)

chip = env.get_template('CHIP.j2')


class Value(object):
    def __init__(self, typ, mn, mx):
        self.typ = typ if typ else (mn + mx) / 2
        self.mn = mn
        self.mx = mx

    def __str__(self):
        return "(typ={:0.2f}, min={:0.2f}, max={:0.2f})".format(self.typ, self.mn, self.mx)


grid_re = re.compile("([0-9]+)x([0-9]+)")

def parse_courtyard(grid):
    (grid_y, grid_x) = grid_re.match(grid).groups()
    return (float(grid_x) * 0.5 / 2, float(grid_y) * 0.5 / 2)

def auto_str(cls):
    def __str__(self):
        return '%s(%s)' % (
            type(self).__name__,
            ', '.join('%s=%s' % item for item in vars(self).items())
        )
    cls.__str__ = __str__
    return cls


_mm_to_in = {
    "1005": "0402",
}

@auto_str
class ChipDimensions(object):
    def __init__(self, **kw):
        for k, v in kw.items():
            setattr(self, k, v)

    @staticmethod
    def from_ipc(data):
        print("data={}".format(data))
        size_mm = data["size_mm"]
#        print("x={}".format(grid_re.match(data["grid"]).groups()))
        return ChipLandPattern(
            key = size_mm,
            size_x = Value(float(size_mm[0:2]) / 10, data["l_max"], data["l_min"]),
            size_y = Value(float(size_mm[2:4]) / 10, data["w_max"], data["w_min"]),
            terminal_size = Value(None, data["t_min"], data["t_max"]),
            height_max = data["h_max"])

@auto_str
class ChipLandPattern(object):
    def __init__(self, **kw):
        for k, v in kw.items():
            setattr(self, k, v)

    @staticmethod
    def from_ipc(data):
        # print("data={}".format(data))
        size_mm = data["size_mm"]
        # try:
        #     size_in = _mm_to_in[size_mm]
        # except KeyError:
        #     print("Missing mm to in mapping for {}".format(size_mm), file=sys.stderr)
        #     sys.exit(1)
        (courtyard_x, courtyard_y) = parse_courtyard(data["grid"])
        r = lambda x: round(x)
        return ChipLandPattern(
            key = size_mm,
            size_mm = size_mm,
            size_in = data["size_in"],
            size_x = float(size_mm[0:2]) / 10,
            size_y = float(size_mm[2:4]) / 10,
            pad_pos_x = float(data["c"]) / 2,
            pad_size_x = float(data["y"]),
            pad_size_y = float(data["x"]),
            courtyard_x = courtyard_x, courtyard_y = courtyard_y)

resc_heights = {
    "1005": [0.15, 0.35, 0.37, 0.40],
    "1608": [0.40],
    "2012": [0.40],
    "3216": [0.40],
    "3225": [0.40],
    "5025": [0.40],
    "6332": [0.40],
    "7142": [0.89],
}

capc_heights = {
    "1005": [0.15, 0.35, 0.37, 0.40, 0.50],
    "1608": [0.40],
    "2012": [0.40, 1.25, 1.35],
    "3216": [0.40],
    "3225": [0.40],
    "4532": [0.40],
    "4564": [0.40],
}

ledsc_heights = {
# https://www.digikey.com/products/en/optoelectronics/led-indication-discrete/105?k=&pkeyword=&pv16=4&FV=ffe00069%2C1140003&mnonly=0&ColumnSort=0&page=1&quantity=0&ptm=0&fid=0&pageSize=100
    # 0402
    "1005": [0.25, 0.35, 0.40, 0.45, 0.50, 0.52, 0.55, 0.60, 0.70, 0.71],
    # 0603
    "1608": [0.20, 0.25, 0.28, 0.30, 0.35, 0.39, 0.40, 0.42, 0.45, 0.46, 0.50, 0.52, 0.55, 0.60, 0.65, 0.70, 0.71, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.05, 1.10, 1.15],
    # 0805
    "2012": [0.40, 0.45, 0.50, 0.70, 0.75, 0.79, 0.80, 0.84, 0.85, 0.90, 1.00, 1.10, 1.20, 1.25, 1.30, 2.10],
    # 1206
    "3216": [0.60, 0.68, 0.69, 0.70, 0.75, 1.00, 1.05, 1.10, 1.20, 1.25, 1.30, 1.38, 1.40, 1.50, 1.60, 1.62, 1.75, 1.80, 1.85, 1.87, 1.90, 1.95, 2.00, 2.05, 2.10],
}

#resc_dims = [ChipDimensions.from_ipc(p) for p in ipc_sm_782.data["resc"]["dimensions"]]
resc_land_patterns = ipc_sm_782.data["resc"]["land_patterns"]
# Some extra custom patterns
if False:
    resc_land_dimensions.append({
        "size_mm": "710420",
        "size_in": "2816",
        "l_min": 7.10 - 0.2,
        "l_max": 7.10 + 0.2,
#        "s_min":
#        "s_max":
        "w_min": 4.20 - 0.2,
        "w_max": 4.20 + 0.2,
#        "t_min":
#        "t_max":
#        "h_max":
    })
    resc_land_patterns.append({
#        "rlp_no":
        "size_mm": "7142",
        "size_in": "2816",
#        "z":
#        "g":
#        "x":
#        "y":
#        "c":
        "grid": "10x10",
    })
resc_lp = [ChipLandPattern.from_ipc(p) for p in resc_land_patterns]
#capc_dims = [ChipDimensions.from_ipc(p) for p in ipc_sm_782.data["capc"]["dimensions"]]

capc_lp = [ChipLandPattern.from_ipc(p) for p in ipc_sm_782.data["capc"]["land_patterns"]]
# We borrow the CAPC land patterns
ledsc_lp = [ChipLandPattern.from_ipc(p) for p in ipc_sm_782.data["capc"]["land_patterns"]]

work = [\
    ("RESC", resc_lp, resc_heights, "SMD Resistor", "resistor", "${{KISYS3DMOD}}/Resistor_SMD.3dshapes/R_{}_{}Metric.wrl"), \
    ("CAPC", capc_lp, capc_heights, "SMD Capacitor", "capacitor", "${{KISYS3DMOD}}/Capacitor_SMD.3dshapes/C_{}_{}Metric.wrl"), \
    ("LEDSC", ledsc_lp, ledsc_heights, "SMD LED", "LED", "${{KISYS3DMOD}}/LED_SMD.3dshapes/LED_{}_{}Metric.wrl"), \
]
for (kind, lps, heights, description, tags, model3d_pattern) in work:
    basedir = "IPC-7351-{}.pretty".format(kind)
    if not os.path.isdir(basedir):
        os.mkdir(basedir)
    for lp in lps:
#        print("{}_{}".format(kind, lp.key))
#        print("lp={}".format(lp))
#        print("lp={}".format(lp.size_x / 8))
        for h in heights.get(lp.key, []):
            key = "{}_{}x{:03}".format(kind, lp.key, int(h * 100))
#            print("  " + key)

            model3d = model3d_pattern.format(lp.size_in, lp.size_mm)
            env = {
                "lp": lp,
                "key": key,
                "model3d": model3d,
                "tags": tags,
                "description": description,
            }
            kicad_mod = chip.render(env)
            with open(os.path.join(basedir, "{}.kicad_mod".format(key)), "w") as f:
                f.write(kicad_mod)
